function isObjcet(obj) {
  // return typeof obj === 'object' && obj !== null
  // return Object(obj) === obj
}

Object.defineProperty(Object, 'is', {
  enumerable: false,
  configurable: true,
  writable: true,
  value: function (x, y) {
    if (x === y) {
      return x !== 0 || 1 / x === 1 / y
    }
    return x !== x && y !== y
  },
})

class Scheduler {
  constructor(limit) {
    this.maxCount = limit
    this.queue = []
    this.runCounts = 0
  }
  add(time, v) {
    const promiseCreator = () => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log(v)
          resolve()
        }, time)
      })
    }
    this.queue.push(promiseCreator)
  }
  taskStart() {
    for (let i = 0; i < this.maxCount; i++) {
      this.request()
    }
  }
  request() {
    if (!this.queue.length || this.runCounts > this.maxCount) return
    this.runCounts += 1
    this.queue
      .shift()()
      .then(() => {
        this.runCounts -= 1
        this.request()
      })
  }
}

let scheduler = new Scheduler(2)

function addTask(time, v) {
  scheduler.add(time, v)
}
addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')
// 的输出顺序是：2 3 1 4
scheduler.taskStart()

function myNew() {
  const args = [].slice.call(arguments)
  const constructor = args.shift()
  const context = Object.create(constructor.prototype)

  const result = constructor.call(context, args)

  return typeof result === 'object' && result !== null ? result : context
}

Function.prototype.myCall = function (context, ...args) {}

// 数组方法手写
// map
Array.prototype.myMap = function (fn, context) {
  const arr = Array.prototype.slice.call(this)
  //   let result = []
  //   for (let i = 0; i < arr.length; i++) {
  //     if (!arr.hasOwnProperty(i)) continue
  //     result.push(fn.call(context, arr[i], i, this))
  //   }
  //   return result
  return arr.reduce(function (pre, cur, index) {
    return [...pre, fn.call(context, cur, index, this)]
  }, [])
}

// filter
Array.prototype.myFilter = function (fn, context) {
  const arr = Array.prototype.slice.call(this)
  //   let result = []
  //   for (let i = 0; i < arr.length; i++) {
  //     if (!arr.hasOwnProperty(i)) continue
  //     fn.call(context, arr[i], i, this) && result.push(arr[i])
  //   }
  //   return result

  arr.reduce(function (pre, cur, index) {
    return fn.call(context, cur, index, this) ? [...pre, cur] : [...pre]
  }, [])
}
// some
Array.prototype.mySome = function (fn, context) {
  const arr = Array.prototype.slice.call(this)

  for (let i = 0; i < arr.length; i++) {
    if (!arr.hasOwnProperty(i)) continue
    let r = fn.call(context, arr[i], i, this)
    if (r) return true
  }
  return false
}

Array.prototype.myEvery = function (fn, context) {
  const arr = Array.prototype.slice.call(this)

  for (let i = 0; i < arr.length; i++) {
    if (!arr.hasOwnProperty(i)) continue
    let r = fn.call(context, arr[i], i, this)
    if (!r) return false
  }
  return true
}

function debounce(fn, time) {
  let timer = null
  return function () {
    if (timer) clearTimeout(timer)
    timer = setTimeout(() => {
      fn.call(this, arguments)
      timer = null
    }, time)
  }
}

function throttle(fn, time) {
  let timer = null
  return function () {
    if (timer) return
    timer = setTimeout(() => {
      fn.call(this, arguments)
      timer = null
    }, time)
  }
}
// 取消 promise 方法1 利用 promies.race() 方法，让一个promise变成手动控制，另一个交给定时器或者其他事件控制
function wrap(p) {
  let obj = {}
  let promise1 = new Promise((resolve, reject) => {
    obj.resolve = resolve
    obj.reject = reject
  })
  obj.promise = Promise.race([promise1, p])
  return obj
}

let promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(2)
  }, 1000)
})
let promise3 = wrap(promise2)
promise3.promise.then((res) => {
  console.log(res)
})

// 手写 call
Function.prototype.myCall = function (context, ...args) {
  context || (context = window)
  let fn = Symbol()
  context[fn] = this

  let res = context[fn](...args)
  Reflect.deleteProperty(context, fn)
  return res
}
// 手写bind
Function.prototype.myBind = function (context, ...args) {
  context || (context = window)
  let fn = Symbol()
  context[fn] = this
  let _this = this
  let result = function (...innerArgs) {
    if (new.target) {
      this[fn] = _this
      let res = this[fn](...args, ...innerArgs)
      Reflect.deleteProperty(this, fn)
      return (typeof res === 'object' || typeof res === 'function') &&
        res !== null
        ? res
        : this
    } else {
      let res = context[fn](...args, ...innerArgs)
      Reflect.deleteProperty(context, fn)
      return res
    }
  }

  result.prototype = Object.create(this.prototype)
  return result
}

// 深拷贝
function isObject(val) {
  return Object(val) === val
}

function deepCopy(source, hash = new WeakMap()) {
  if (!isObject(source)) return source
  if (hash.has(source)) return hash.get(source)
  let target = Array.isArray(source) ? [] : {}
  hash.set(source, target)
  for (let k of Reflect.ownKeys(source)) {
    if (isObject(source[k])) {
      target[k] = deepCopy(source[k], hash)
    } else {
      target[k] = source[k]
    }
  }
  return target
}

class MyPromise {
  constructor(executor) {
    this.state = 'pending'
    this.value = void 0
    this.reason = void 0

    let resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled'
        this.value = value
      }
    }
    let reject = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = reason
      }
    }
    try {
      executor(resolve, reject)
    } catch {
      reject(err)
    }
  }
}
